﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using System.Text;

namespace SharpDepend.Storage
{
    public class Property
    {
        // Private variables.
        public string Name;
        public string Value;
        
        //------------------------------------------------------------------------------------------------------------------------
        public Property(string name, string value)
        {
            this.Name = name;
            this.Value = value;
        }

        //------------------------------------------------------------------------------------------------------------------------
        public Property(string name, object value)
        {
            this.Name = name;
            this.Value = value.ToString();
        }

        //------------------------------------------------------------------------------------------------------------------------
        public override string ToString()
        {
            return Name + " = " + Value;
        }

        //------------------------------------------------------------------------------------------------------------------------
        public T GetValue<T>()
        {
            return Cache<T>.GenericParse(Value);
        }
    }

    /// <summary>
    /// Helper class that will easley parse string to a generic.
    /// </summary>
    /// <typeparam name="T">string, byte, short, int, float, double, bool</typeparam>
    internal static class Cache<T>
    {
        // Deleagte.
        delegate bool TryPattern(string s, out T value);

        // Private static variables.
        private static readonly TryPattern func;

        //------------------------------------------------------------------------------------------------------------------------
        public static bool TryParse(string s, out T value)
        {
            return func(s, out value);
        }

        //------------------------------------------------------------------------------------------------------------------------
        private static decimal ParseDecimal(string value)
        {
            return 0; // TODO: FIXA!
        }

        //------------------------------------------------------------------------------------------------------------------------
        private static double ParseFloat(string value)
        {
            return Utils.Math.Parse.Double(value);

            //value = value.Replace('.', ',');

            //string[] splitted = value.Split(',');

            //// If integer with deciamls.
            //if (splitted.Length == 2)
            //{
            //    long left = long.Parse(splitted[0]); // Get number before ','.
            //    long right = long.Parse(splitted[1]);// Get number after ','.
            //    double decimals = Math.Pow(10, splitted[1].Length);
            //    double right_decimal = right / (double)(decimals); // Calculate the decimal number.

            //    return left + right_decimal;
            //}
            //else if (splitted.Length == 1)
            //{
            //    return long.Parse(splitted[0]);
            //}

            //throw new Exception("Invalid decimal number.");
        }

        //------------------------------------------------------------------------------------------------------------------------
        public static T GenericParse(string value)
        {
            // If float.
            try
            {
                if (typeof(T) == typeof(double))
                {
                    return (T)(object)ParseFloat(value);
                }
                else if (typeof(T) == typeof(float))
                {
                    return (T)(object)(float)ParseFloat(value);
                }
                else if (typeof(T) == typeof(decimal))
                {
                    return (T)(object)ParseDecimal(value);
                }
                else if (typeof(T) == typeof(byte))
                {
                    return (T)(object)byte.Parse(value);
                }
                else if (typeof(T) == typeof(sbyte))
                {
                    return (T)(object)sbyte.Parse(value);
                }
                else if (typeof(T) == typeof(short))
                {
                    return (T)(object)short.Parse(value);
                }
                else if (typeof(T) == typeof(ushort))
                {
                    return (T)(object)ushort.Parse(value);
                }
                else if (typeof(T) == typeof(int))
                {
                    return (T)(object)int.Parse(value);
                }
                else if (typeof(T) == typeof(uint))
                {
                    return (T)(object)uint.Parse(value);
                }
                else if (typeof(T) == typeof(long))
                {
                    return (T)(object)long.Parse(value);
                }
                else if (typeof(T) == typeof(ulong))
                {
                    return (T)(object)ulong.Parse(value);
                }
            }
            catch (Exception)
            {

            }

            // Create generic instance.
            T valueParsed = default(T);

            // NOTE: Android (Release) Hang here... if (typeof(T) == typeof(ulong)) core above is safer.
            // Parse value to generic.
            if (!Cache<T>.TryParse(value, out valueParsed))
            {
                throw new FormatException("Could not parse value '" + value + "' to type of '" + typeof(T).Name + "'");
            }

            // Return generic.
            return valueParsed;
        }

        //------------------------------------------------------------------------------------------------------------------------
        static Cache()
        {
            MethodInfo method = typeof(T).GetMethod("TryParse",
                new Type[]
                {
                    typeof(string),
                    typeof(T).MakeByRefType()
                });


            if (method == null)
            {
                if (typeof(T) == typeof(string))
                {
                    func = delegate(string x, out T y)
                    {
                        y = (T)(object)x;
                        return true;
                    };
                }
                else
                {
                    func = delegate(string x, out T y)
                    {
                        y = default(T);
                        return false;
                    };
                }
            }
            else
            {
                func = (TryPattern)Delegate.CreateDelegate(typeof(TryPattern), method);
            }
        }
    }
}
